package com.gitee.alg.sort

import org.openjdk.jmh.annotations.Benchmark
import kotlin.system.measureNanoTime

/**
 * Project Name: alg
 * Des:
 * Package:com.gitee.alg.sort
 * @author Arlo Sun
 * @date 2021/4/26 - 11:11
 */
@Benchmark
inline fun <reified T : Comparable<T>> Array<T>.sorting(
    algorithm: Algorithm = Algorithm.BUBBLE,
    ascend: Boolean = true
): Array<T> {
    val sorter = when (algorithm) {
        Algorithm.BUBBLE -> BubbleSort<T>(inlineComparator(ascend))
        Algorithm.SELECTION -> SelectionSort(inlineComparator(ascend))
        Algorithm.SHELL -> ShellSort(inlineComparator(ascend))
        Algorithm.INSERTION -> InsertionSort(inlineComparator(ascend))
        Algorithm.MERGE -> MergeSort(inlineComparator(ascend))
        Algorithm.HEAP -> HeapSort(inlineComparator(ascend))
        Algorithm.QUICK -> QuickSort(inlineComparator(ascend))
        Algorithm.ITERATE_MERGE -> IterateMergeSort(inlineComparator(ascend))
    }

    var res: Array<T>
    val source = this.copyOf()
    val mess = measureNanoTime {
        res = sorter.sort(source, ascend)
    }

    println("-".repeat(96))
    println("Sorting array : Alg => ${algorithm.name}, Ascending => $ascend , cost => $mess ns")
    println("After sorting : ${res.contentToString()}")

    return res
}

fun <T> Array<T>.swap(a: Int, b: Int) {
    if (a != b){
        this[a] = this[b].also { this[b] = this[a] }
    }
}

// partial application routine ...
fun <T : Comparable<T>> inlineComparator(ascend: Boolean): (a: T, b: T) -> Boolean {
    return when (ascend) {
        true -> { a, b -> a > b }
        else -> { a, b -> a < b }
    }
}
